【CSDN 编者按】又是新的一年。承上启下的总结会让人变得清朗,一方面是对过去的总结,另一方面是向往未来。这篇文章总结了前端技术在过去一年的发展,深入浅出,值得一看!
2020 年已经结束,因为疫情,大家的生活和工作或多或少都受到一定影响。尽管如此,但前端技术的发展并没有停止脚步。作为前端开发者,需要对技术的更新换代有所了解。虽然不需要去学习所有新出来的技术,但是时刻保持 “了解” 和 “理解” 是有必要的。本文盘点了 2020 年前端的一些新老技术发展和趋势。
"微前端" 应该是 2020 年里听的最多的一个前端技术。不少大厂在尝试利用这个新技术来解决大型前端项目中的问题。虽然我们前端开发中有模块化(modular)组件(components),但它相比后端的 “微服务” 是大有不同的。在了解 “微前端” 之前,我们先给没有接触过后端的同学补一下后端的 “微服务” 知识。微前端的起源和后端一样,就是一个模块因为业务和功能的持续发展,导致模块内容的代码越来越复杂,越来越庞大,同时就会造成与其他业务有不可避免的互相影响的关系。就是这些模块与模块之间的关系,让我们的系统变得越来越难以维护,大大减低了开发的 “敏捷性”。那么怎么办呢?我们就让一个大型的 app 业务按模块拆分成一个一个小的 “服务” 模块。这些小的模块会与后端的接口一样,放在单独的服务器上运行,同时也会有单独的小团队进行专门的开发和维护。这种微型的独立前端架构体系和系统就叫做 “微前端”。 “微前端” 应用开发团队拥有整个应用生命周期自主性。这就包块独立开发、独立版本号管理、独立测试、独立打包、独立渲染、独立更新、独立部署。在上图中,我们可以看到微前端在一个研发中心里的组织架构。每个微前端团队都会负责一个独立的业务模块,每个模块都会有他们自己的核心业务。与其他业务的功能其实是相对独立的,但是业务的流程上他们就会通过数据流、交互流、接口等方面串联起来。最终用户所体验到的系统,其实跟我们普通的应用没有什么区别。但是从大型应用开发和维护的角度来看,好处甚多。- 自主性 —— 可以对每一个微前端应用进行独立的开发、部署、维护和扩展,而不影响其他微前端应用的功能。
- 专用性 —— 每个微前端应用都是针对一组功能而设计的,并专注于解决特定的问题。如果开发者逐渐讲更多的代码增加到一项微前端应用当中,从而让这个微前端应用变得复杂时,那么我们可以将其再次拆分成多项小的微前端应用。
- 敏捷性 —— 微前端是由若干个小型独立团队形成的一个组织,这些团队负责自己的微前端应用。个团队在小型而易于理解的环境中进行开发,并且可以更独立,更快速地工作。这个缩短了开发周期的时间。
- 灵活扩展 —— 通过微前端化应用,我们可以独立扩展组件和功能来满足其他应用的需求。这使团队能够适当调整基础设施需求,准确的衡量功能成本,并在服务需求激增时保持可用性。
- 轻松部署 —— 微前端支持持续集成和持续交付,可以轻松和放心的尝试新的想法,并可以在无法正常运行时独立回滚某一个应用。由于微前端应用直接都是独立的,所以问题只会发生在自己的应用当中,所以我们可以大胆的试验,更轻松地更新代码,并缩短新功能的上线时间。
- 技术自由 —— 微前端架构不遵循 “一刀切” 的方法。团队可以自由选择最佳的工具或者框架来解决他们的具体问题。也就是说一个微前端应用可能是用 Vue,然后另外一个可能是用 React 也不是不可以的。因此,构建微服务的团队可以为每项作业选择最佳的工具或者框架。
- 可重复使用 —— 将前端应用划分成明确定义的模块,让团队可以将功能用于多种目的。转为某项功能编写的前端模块可以用作另一项功能的构建块。这样应用程序就可以自行引导,因为开发者可以创建新的功能,而无需冲头开始编写代码。
- 弹性 —— 前端应用独立增加了应用程序应对故障的弹性。在整体式架构中,如果一个组件出现故障,可能导致整个应用程序无法运行。通过微前端的拆分架构,应用程序可以通过降低功能而不导致整个应用程序崩溃来处理总体服务故障。
这里幻想一下,我们有一个博客主页。主要功能就是为了展示文章内容。当然一个博客其实很简单,在正常开发场景下,也不会给它做微前端的架构设计。- 首先当用户进入首页,可以看到文章的列表,并且用户可以通过关键词来搜索文章。同时也可以通过分类、标签来搜索。更复杂一点的话,我们还可以根据阅读量,热度(通过算法计算热度)来排序和搜索。
- 每一篇文章必然会有一个详情页,每个详情页都需要展示文章的详细文本。如果想加大难度的话,我们还可以根据标签和用户日常的文章浏览记录,来推算用户会对其他什么文章感兴趣。这个时候就可以加入相关推荐的文章列表了。
- 那么是博客的,必然就会有博主的介绍页(About)、文章分类页(Categories)、文章标签页(Tags)。
当然这个还不是很复杂,但是当我们继续往这个博客平台加入更多的功能,比如最后做成 CSDN 这样的平台的时候,那么微前端就有必要了!好,如果真的有那么一天,我们变成一个很大的博客平台。那么我们要怎么运用微前端呢?其实集成方法有很多种:- 服务器端模板组合 (Server-side template composition)
- 构建时集成 (Build-time integration)
- 通过 iframes 在运行时集成 (Run-time integration via iframes)
- 通过 JavaScript 在运行时集成 (Run-time integration via JavaScript)
- 通过 Web 组件在运行时集成 (Run-time integration via Web Components)
其实所有的集成方法,都围绕着一个很自然的设计模式 —— 一个应用里面的每个页面都是一个 “单独的” 微前端应用。而在每个页面中都会有一个“单独的应用容器(single container application),而它的作用就是:- 渲染页面公共头部(headers)和脚步(footers)
- 解决 “横切关注点(Cross-cutting concern)”,比如身份验证和导航
- 把多个微前端应用放在一个页面之中,并且告诉每个微前端应用在什么时候和在哪里渲染到页面上。
注意这里只讲到微前端的皮毛,其实微前端最核心并不在前端,更多的难点都是在 “云服务器”。如果没有服务器架构、部署、测试等等的支撑,微前端是很难以实现的。所以在一般公司的应用场景,其实根本用不上微前端。
原子设计也是在 2020 年里提到的非常多的一个概念。不过这个更多只是一个概念,并不是一个纯方法论。这个概念是 Brad Frost 提出的,他用化学中的原子组成来分析和拆解一个 Web 应用的组成成分。里面包含原子(Atoms)、分子(Molecules)、生物(Organisms)等。比如一个搜索分子(Search Molecule)就是由 input-text(输入文本)+ button(按钮)+ label(标题)等原子所组成。然后这些分子组合起来就会变成一个生物(Organism)。而生物(Organism)就会生存在我们页面的布局模版之中,而这些就可以具体化成一个页面,最后显示给到我们的用户。Brad Frost 把前端的组件和界面设计抽象成化学中的原子组成结构。让我们更加清晰的去理解一个页面、一个组件、一个元素的组成方式。其实这个概念可以让我们用一个全新的角度去看待模块化 UI(modular UI)。这种思维方式让我们更深入的理解一个组件的作用和 API,从而在设计组件的时候会更加的清晰和高效。原子是物质的基本组成部分。而在组件设计中,原子就是一个组件的最小元素单位,一个组件都是用多个原子所组成的。原子单独使用是没有任何意义的,一般都是需要组合其他原子一起使用才能真正发挥它们的作用。当我们把原子(Atoms)结合在一起时,事情开始变得更加的有趣。分子(Molecule)是一组结合在一起的原子,是化合物中最小的基本单位。每一个分子都有自己的特性,是我们设计系统的支柱(Backbone)。比如,一个表格标题、输入框、按钮等元素,它们单独使用时没有太大用处的。但是如果我们把它们组合在一起,变成一个表格。这个时候它们就可以使用了。在我们用原子组合分子时,我们需要遵循一个原则:“只做一件事,并且做好”。(这个听起来是不是有点像设计模式里面的:“单一职责”?是的,就是这个意思。)虽然分子可能很复杂,但根据经验,他们相对而然都是一些简单的原子而组成的,主要是为了可复用性而生。分子可以作为我们组建界面的积木。我们可以把分子组合在一起来建立一个生物体(也就是我们的一个界面)。生物是用一组分子组合而成的,而组成的生物体是界面的其中一部分,它有相对复杂,独特的特性。就比如上图,我们在组合了一个网页 logo 部分的分子。然后我们把搜索分子和 logo 分子再组合在一起,就变成了界面上头部(生物体)的部分(header organism)。这个就会开始变得越来越有趣了,生物不是一个固定的组件,它是用多个分子所组合而成。不同的生物体可能存在使用相同的分子或者原子,但是他们的作用都是有所不同的。就比如,我们的 logo 和文章图片两个不同的分子,他们相同都使用了 img 图片标签这个原子。但是这个 img 原子是放在了两个不同职责的分子里面,一个是用在头部作为 logo 展示的,一个是用在文章列表用来展示图片的。所以在组建分子和用分子组件生物体的时候,我们创建的组件必须是独立的、可移植、可重用的。有了分子组成的生物体(Organism)后, 我们就可以用这些生物体来组件我们的界面模版。这里我们就可以打破化学的类比,拥有对用户和最终输出更有意义的东西。模版主要是由多个生物体缝合在一起而形成的页面。在这里,我们开始看到组件和模块的设计开始融合在一起,可以看到布局之类的东西开始有所体现了。模版是非常具体化的,它为所有的这些相对抽象的分子和生物体提供了上下文。模版阶段也是用户可以开始看到设计界面的地方。根据这个设计的创作者 Brad Frost 的使用经验,模版一开始是 HTML 线框,但随着时间的推移,它的保真度会逐渐提高,最终成为可交付的产品。页面(pages)是模版的特定实例。这里,占位符内容被真实的,有代表性的内容所取代,以准确地表现方式描述了用户最终将要看到的内容。页面是最真实的,因为它们是最有形态的,它通常是大多数人在开发过程中花最多时间来处理和优化的部分。页面这个阶段非常的重要,因为这里是我们测试设计系统有效性的地方。在上下本中查看一切,是我们能够回头来修改我们的分子(Molecules)、生物体(Organism)和模版(Templates)。页面也是测试模版变化的地方。例如,我们可能想清楚地表达包含40个字符的标题最终展示到给用户是什么样子的,但是也想演示340个字符是什么样子。当用户的购物车中有一件商品与应用了折扣的时候,商品的展示会是怎么样的。这些实际的情况会影响我们如何循环和构建我们的应用。我们简单理解了原子设计后,我们就可以问问,为什么要用原子设计呢?其实答案很简单,我们平时去设计一个应用的时候,即使我们没有意识去使用这种思维方式,但是我们一直都是以这种方式在设计的。原子设计为设计系统提供了一种清晰的方式轮(概念为主),团队成员(开发者、产品经理、设计师等)能够通过实际看到的,摆在他们面前的步骤来更好地理解设计系统的概念。原子设计赋予我们从抽象到具体的能力。正因如此,我们可以创建促进一致性和可伸缩性的系统,同时在最终的欢迎中显示内容。重点是通过组合而不是解耦的方式来构建应用。我们在一开始就创造了一个系统,而不是在事后才去挑选模式。
组件开发最重要的一个方面是封装(Encapsulation)—— 就是能把标记(markup)和行为隐藏起来,并与页面上的其他代码分开,这样不同的部分就不会冲突,代码也可以保持整洁。而要做到这样,Shadow DOM API 就是关键。它可以将一个隐藏的、独立的 DOM 附加到一个元素上。Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中 —— 它以 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样。- Shadow host:一个常规 DOM节点,Shadow DOM 会被附加到这个节点上。
- Shadow tree:Shadow DOM内部的DOM树。
- Shadow boundary:Shadow DOM结束的地方,也是常规 DOM开始的地方。
- Shadow root: Shadow tree的根节点。
我们可以使用与常规 DOM 一样的方式来操作 Shadow DOM —— 例如,添加一个子节点、设置属性、以及为节点添加自己的样式,或者为整个 Shadow DOM 添加样式。与不同 DOM 不一样的是,Shadow DOM 内部的元素始终不会影响它外部的元素(除了 :focus-within),这为封装提供了便利。其实 Shadow DOM 并不是一个全新的东西,它已经被浏览器使用了很长一段时间了。浏览器用它来封装一个写元素的内部结构,以一个有着默认播放控制按钮 <video> 元素为例。我们所能看到的只是一个 <video> 标签,实际上,在它的 Shadow DOM 中,包含了一系列的按钮和其他控制器。Shadow DOM 标准允许我们自己的元素(custom element)维护一组 Shadow DOM。这种方式也常常被认同为是组件样式封装的最佳解决方案。首先我们可以使用 Element.attachShadow() 方法来将一个 shadow root 附加到任何一个元素上。这个方法接受一个配置对象作为参数,这个对象有一个 mode 属性,它的值可以是 open 或者 closed:let shadow = elementRef.attachShadow({mode: 'open'});
let shadow = elementRef.attachShadow({mode: 'closed'});
open:表示可以通过页面内的 JavaScript 方法来获取 Shadow DOM, 例如使用 Element.shadowRoot 属性:let myShadowDOM = myCustomElem.shadowRoot;
但是如果我们把 Shadow root 附加到一个自定义元素(Custom element)上,并且把 mode 设置为 closed,那么我们就不可以从外部获取到 Shadow DOM 了 —— myCustomElem.shadowRoot 将会返回 null。其实浏览器中的 <video> 就是这样的,里面就包换了一个不可访问的 Shadow DOM。如果你想将一个 Shadow DOM 附加到 custom element 上,可以在 custom element 的构造函数中添加如下实现(目前,这是 shadow DOM 最实用的用法):let shadow = this.attachShadow({mode: 'open'});
将 Shadow DOM 附加到一个元素之后,就可以使用 DOM APIs对它进行操作,就和处理常规 DOM 一样。var para = document.createElement('p');
shadow.appendChild(para);
详细的使用方式,可以直接去看 MDN 的 《使用 shadow DOM》。
有报告统计,80% 的开发者承认想在下一个项目中使用或者学习 TypeScript。虽然 TypeScript 还有它的缺点,但它让代码更容易理解(对于习惯编写面向对象的同学,确实好理解,但是不熟悉面向对象的同学,就有点难受了)。并且 TypeScript 可以更利于快速实现。那么我们应不应该转 TypeScript 呢?在决定之前,我们还是冷静一下,看看使用 TypeScript 的优缺点,然后根据我们自己团队的技术情况再做选择才是合理的。很多时候当我们在看一段代码中的一个函数,我们都会问以下问题:但是在像 TypeScript 这样的静态类型语言中,我们可以立即从 IDE 和编译器中得到上述的所有问题的答案。不再需要查看整个代码库,不断地向我们的同事提出问题,或者在生产上出错误的风险。当我想要实现一个新的功能或者组件,我们的工作流大概是这样子的:- 初始化组件函数,建立它的构造函数参数,编写剩下的代码。
- 如果它需要任何外部或复杂的数据(如用户或文章),那么就要将它保存在我们自己的内存中,并在代码中使用它。
- 将组件放入你的应用中,并将 props 传递给它。
- 然后就是测试这个组件,手动或者使用单元测试(这里我们需要确保它能接收到该有的 props,并且它能正常工作。)
- 如果有什么地方出现了 bug,那么就要回到我们的代码,试着找到哪里出了问题。再回到第 1 步。
上述是在使用 JavaScript 的开发流,那么如果我们用的是 TypeScript 的话就会变得更简单,更高效了:- 如果它需要任何外部或复杂的数据,直接查找它们的接口并重用它们(全部或部分)。
- 将组件放入你的应用中,并将 props 传递给它。
- 就是这样!(如果在调用者和被调用者之间正确地匹配了类型定义,那么一切都应该能够完美地工作。现在唯一需要测试的是组件的实际业务逻辑。)
是不是简单很多了?这个也是为什么 TypeScript 出现的低级错误会更少的原因。在开发中,我们肯定是会有很多代码在编写后,都需要我们去重构的。但是因为往往都涉及太多的东西和文件,所以我们开发者一听到一个项目需要重构代码基本都是这样:在 TypeScript 中,这类重构的事情变得不那么可怕。往往一个重构只需要轻轻在 IDE 的按一下 “重命名符号(Rename Symbol)” 命令即可。在动态类型语言中,同时重构多个文件时,我们能得到的最好的帮助就是使用RegExp 进行搜索和替换。而在静态类型语言中,不再需要搜索和替换了。使用IDE命令,如“查找所有出现的情况”和“重命名符号”,可以看到应用程序中特定的函数、类或对象接口属性的所有出现情况。如果我们想稍微改进我们的构建系统、重命名组件、还是修改对象或者删除废弃的属性,我们都不必担心破坏任何东西。TypeScript 会帮助我们找到重构后的这些相关联的东西的用法,重新命名它,并如果在我们重构后出现了类型不匹配的情况,它就会发出编译错误的警告。做了多年的前端开发,我们都知道如果有一个人在我们旁边,在我们拼写错变量名、使用了一个不一定会是 null 的值、或者传了一个对象类型参数给一个接收数组类型的函数的时候提醒一下我们,那么我们就可以省下 50% 的排错时间。很高兴的告诉大家,这个好基友就是 TypeScript。多谢它,现在想编写一个 bug 也变得相对难了。当我们的代码打包的时候,我们可以大概知道我们的代码是可以运行的通的。当我们确定我们传的参数是对的,那么我们就不用去测试所有地方调用了某个方法是否会报错,对方有没有用对参数,用对类型,用对我们提供的方法。少了这些的顾虑,我们就可以更多的集中在编写业务逻辑的单元测试,而不是代码的语法和准确性的保障测试。既然我们减少了检测代码中报错的问题,我们就可以花更短的时间来完成新功能和需求。这样我们的代码就不会很复杂,更不容易出错,更容易维护。当我们在编写静态类型语言时,首先我们需要想,我们需要的数据类型是怎么样的,然后想我们想产出的数据又是怎么样的。这个过程就需要在我们坐下来开始写代码之前就要想清楚。其实还有很多同学在开始实现一个功能和需求之前,缺乏了思考和分析。没有认真的思考过整个代码和逻辑的思路、实现的方法、数据的类型、函数的结构等。但是对于老司机程序员来说,很多都是先思考然后才去动键盘的。那么 TypeScript 就会要求我们遵循这种好的开发思维。它鼓励我们在坐下来实现功能和代码之前,先要考虑清楚我们要实现的功能的接口类。说了那么多 TypeScript 的优点,我们也来讲讲它的缺点。如果我们是开发 Node.js 后端的开发者,如果使用 TypeScript 确实会变得比较麻烦。因为我们需要先编译了 .ts 的文件,然后才能在 Node 上去运行。当然如果我们有一个好的打包工具链,这个问题还是可以解决的。但是确实会 Node.js 后端的同学带来本来没有的麻烦。不过相对前端开发者来说,这个并不是任何问题。因为现代的前端开发流程,我们都会把所有的前端代码通过 webpack、grunt 等打包工具我编译我们的代码。那么 .ts 文件在这个过程已经自动的帮我们编译过来了。所以我们不需要做任何附加的步骤。顶多也是多在打包工具中使用 npm 多安装一个编译插件。不可置疑,这一点确实是事实。比如,在普通 Next.js 和使用 TypeScript 的 Next.js 之间,使用了 TypeScript 我们就要附加 Node.js 服务器、webpack 和 jest test 测试工具。还有,当我们需要添加一个像 React、Redux、Styled-Components 等 library 的时候,我们都要为他们附加 typedefs。(比如 @types/styled-components,不过有一些包本身就自带有 TS typedefs 文件)不过我觉得这些问题并不大,因为在长期开发和维护一个项目的过程中,安装依赖包和设置一个 TypeScript 项目,相对比我们平时编写算法和业务逻辑的评率,其实是非常微小的一部分。基本上这些繁琐的事情都是一次过搞好就行,如果还是觉得繁琐,做一个 toolchain 工具,每次需要操作这些重复的事情的时候,直接用工具帮我们构建即可。TypeScript 固然是好,毕竟 Vue 3 的重构中也在很多语言中最后选择了 TypeScript 作为他们的核心语言。所以 TypeScript 的好处是显而易见的。但是任何的技术选型都要看我们自己所在的团队和公司。如果有 10 个开发,9 个都不会 TypeScript,并且都不太愿意去学,或者公司根本给不到时间让我们团队去学习新的语言。
因为纯 Web 组件与任何的前端框架无关,他们可以在没有框架或者使用任何框架的情况下工作。因为这些组件更加不受 “JS 疲劳(JavaScript Fatigue)” 所控制,并且大部分浏览器都是支持的。因为它们的包大小和消耗是更有优势的,加上 VDOM 渲染拥有令人震惊的能力。这些组件提供了自定义元素、一个 Javascript API (允许我们定义一种新的 html 标记)、html 模板来指定布局,当然还有 Shadow DOM(本质上是特定于组件的)。这里解释一下什么是 JS 疲劳 —— 就是当我们想学习前端的时候,第一个接触的语言必然就是 JavaScript,但是一旦开展学习后,就会发现这个水是真的深,一大窜的其他关联知识就会如同潮水一样扑面而来。包括,前端框架、Node.js、UI 框架、浏览器知识、工具链等等。学习前端一开始确实是一个非常疲劳的一个领域。当我们思考未来 UI 开发,以及模块化、可重用性、封装性和标准化的原则时,组件(化)时代应该是怎么样子时,Web 组件就会浮现在未来的蓝图上。
无论是 React 的 Redux 还是 Vue 的 Vuex 其实都是特别难搞的大魔头。尽管随着前端变得越来越模块化,在应用程序中的全局状态管理变得越来越难以控制。但是状态管理(State Management) 像 Redux 和 Vuex 的实用性和实用性使他们成为许多团队的首选解决方案。所以我们在 2020 年之后可以和 Redux 说再见了吗?不,不完全可以。然而,在前端框架中的状态管理体系不断的涌现(如 React hook、Context-API 等),未来很有可能会废除掉对框架以外的状态管理的依赖。像 Mobx,一开始这些类型技术还很少被采用,但是由于它们面向组件和可延伸性的特性,仅仅在 2020 年这一年内,它们开始变得越来越流行,让我们开发这可以在探索更多的选择。MobX 是一个经过战火洗礼的库,它通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。MobX 背后的哲学很简单:
ES 模块就是在浏览器使用模块时的标准,而 ES 模块就是被 ECMAScript 所标准化的。使用 ES 模块,你可以很容易地将功能封装到模块中,这些模块可以通过 CDN 来使用。随着 Firefox 60 的发布,所有主流浏览器都将支持 ES 模块,Node mteam 正在努力向 Node.js 中添加 ES 模块的支持。此外,WebAssembly 的 ES 模块集成也将在未来几年内推出。
渐进式网络应用也叫 Progressive Web Apps —— 它利用最新的技术将网页和移动应用程序的有点结合起来。可以把 PWA 想成一个使用 Web 技术的网站,但是行为和感觉是一个应用程序(APP)。最近在浏览器、服务的可用性 worker、Push APIs 的发展与进步,允许用户在主界面安装 Web 应用程序,甚至接收推送通知和离线工作。由于 PWA 是提供了亲密的用户体验,而且所有的网络请求都可以通过 service worker 被拦截。因此,必须将应用托管在 HTTPS 上,从而防止 “中间人” 攻击,这也意味着更好的安全性。当然,PWAs 仍然有局限性,它们不能完全替代本地应用。(不过,它们真的需要那么做吗?)特别是,由于本质上是网页,PWAs 不能使用大多数硬件功能,如 NFC 和蓝牙。然而,并不是所有的应用程序都需要这些功能。不过 PWAs 开发起来更快、更容易、更便宜,这就是为什么它们在 2020 年成为开发的趋势,并且在下一年肯定会继续成为趋势的原因。
JavaScript 很棒,但是也不是没有缺点。JavaScript 是存在有性能的问题的。所有解析醒语言都面临同样的问题,而 WebAssembly 是解决这个问题的最新途径。WebAssembly 最好的一个点是,它并不是一门全新的语言。我们可以用自己喜欢的语言来编写,然后将其编译成 WASM 文件,以便在浏览器中运行。WebAsssembly 目前支持的语言有 C/c++、Elixir、Python、Go、c#/.Net 和 Java。WebAssembly 不是最近才有的,它已经上市好几年了。但它发展的迅速,提供了越来越多的选择。默认情况下,现在所有主流浏览器都支持它,如果程序员 能拥有它是一件非常有益的事情。
可访问性,也叫 Accessibility —— 这是 Web 应用层序开发中最重要的东西之一。我们相信可访问性,应该是每一个网站开发者的任务列表的收腰任务,不经是新网站,而旧网站的更新也是一样。可访问性(或 a11y)是一个计算机系统对用户的 “方便性” 的考量原则。网站应该能在各种设备上正常运行。但它们应该适用于各种“障碍”和“残疾”的用户。A11y 通常指软件和硬件的可访问性。a11y 这个名字来自于 “accessibility” 中有 13 个字母,所以在 “a” 和 "y" 之间有 11 个字母。但如果你仔细看,a11y 看起来像 “ally” 这个词 —— 意思是朋友、助手、拍档的意思。
JavaScript 框架 (Frameworks)
最后我们来讲以下 2020 年中一些我们可以关注以下的前端框架。Gatsby 是一个 SSG,全称是 Static Site Generator(静态站点生成器)。如果我们认为静态站点已经成为过去,反而它们输入全新的技术趋势。GatsbyJs 最大的优点之一是它不需要传统的服务器;它与 BYOC(Bring Your Own Content —— 自带内容)一起工作,可以基于 CMS、CSV、API 和 markdown 文件中的数据构建网站。Gatsby 还使用一种高端 API 查询语言 GraphQL 来构建数据层。掌握 GatsbyJs 要求开发者了解 React Native 和/或 GraphQL,但我们不需要马上就有深入的知识 —— 我们可以同时学习 Gatsby + React Native + GraphQL,也就是边学着做 Gatsby 边学习 React 和 GraphQL。因为 GatsbyJs 是一个 SSG,所以它非常适合开发电子商务网站。这个基于 React 的生成器,可以帮助我们在一瞬间就能加载完网站。我们这里说的不是秒,而是毫秒级的加载速度。任何电子商务企业所有者都知道,有时页面加载时的延迟,会对客户是否购买产品产生很大的影响。这个也适用于其他类型的网站。在 2019 年的 6 月底,Evan You(尤雨溪)和 vuejs 背后的团队发布了一个关于 Vue 3 框架的新迭代的 RFC(征求意见 —— Request For Comment),在社区中遇到了相当多的否定。但是最后这个事实证明,这些负面的反馈并没有那么影响 Vue 3。一些 Web 开发者陷入困境,因为 Vue.js 突然有了一个基于函数的组件 API(Component API)来取代大部分人已经熟悉的对象 API。然而,这并不完全正确,新的基于函数的组件 API 是对排序的补充,如果我们愿意,我们是可以与传统的对象 API 一起使用的。Vue 3 组合 API 中的新语法具有更好的逻辑性,有助于更好的代码结构。一些开发者甚至说它稍微缩短了代码。而且 Vue 3 架构可以作为 Vue 2 的插件使用,只需要使用 Vue Composition(组合式) 库即可。然后在 2020 年 9 月 18 日,Vue 3 的正式版发布了,命名为 One Piece(这个名字很多同学一看就知道来源于海贼王)。- 双向相应原理由 Object.defineProptry 改为基于ES6 的 Proxy,这样使颗粒度更大,速度更快,从而消除了之前存在的警告;
支持了 tree-shaking(剪枝):像修剪树叶一样把不需要的东西给剪切掉,这样 Vue 3 的体积就变得更小了。因为有了 tree-shaking,vue 3 中的模块只有需要的时候才会被打入到包里、优化后的 Vue 3 的打包出来的体积将会是原来的一半(仅 13kb)。就算我们把所有的功能都引入了,打包出来也只有 23kb,依然还是比 Vue 2.x 更小。有了这个,像 keep-alive、transition、甚至 v-for 都是可以按需引入了。其实 Composition API 的灵感来自于 React Hooks, 它是比 mixin 更强大的存在。它可以提高代码逻辑的复用性,从而实现与模版的独立性;同时函数式的编程代码的可压缩性更强。另外,Reactivity 在 Vue 3 中独立开来,意味着 Vue 3 的响应式模块可以与任何其他的框架相组合使用。不再限制 template 只有一个根结点。并且 render 函数也支持返回数组,有点想 React 中的 React.Fragments。Vue 3 拥有更好的类型推导,使得 TypeScript 的支持变得非常好。Rich Harris 在 2019 年的 JSConf EU 上发布,Svelte(中文意思是 “苗条”)与 Vue相似又不同。类似的是,它也是一个组件架构。然而,与 Vue 不同的是,Svelte 的组件编译器是在构建时(Build Time)运行的。这使得我们可以只加载需要展示目前 APP 的组件。我们不需要使用任何的虚拟 DOM(Virtual DOM)。Svelte 使用一套简单的语法,使开发者能够从标记访问变量,而不是使用每个框架都不一样的状态包装器(state wrapper)。这就使得 Svelte 成为 Web 开发新手的一个近乎完美的框架(就是非常好上手)。而对于有丰富经验的开发者来说,Svelte 意味着可以更快地编写代码,从而获得更高性能的网站。在它发布之后的一年里,Svelte 经历了许多的重大改进和更新,最终形成了许多开发人员现在所说的,最简单和最漂亮的框架之一。
框架就是为了使一切变得更简单,其中包括被众多历史遗留困扰的 CSS。让我们看看 2020 年里 CSS 中流行的技术。在最新的 Web 发展趋势中,Houdini(取名于著名的魔术师 Harry Houdini)是一个非常独特的框架。基本上,Houdini 是一个 API 集合,为开发者提供了对 CSS 对象模型的访问。这个意味着,如果你需要 CSS 中还没有的样式,没有必要用 JavaScript 去修改或者覆盖。我们直接使用 Houdini CSS 架构,就可以编写被浏览器视为 CSS 并被解析的代码去操作样式。使用这种方式可以使解析花费的时间更少,开发者不需要等待浏览器提供商扩展的 CSS,设计可以变得更加易于定制和更独特。不过还有一个问题:并不是所有的主流浏览器都支持 Houdini。但是现在我们只能等待这个框架被所有主流浏览器支持。Bulma 是现代的行业趋势之一。他是用 Sass 扩展构建的,基于 CSS 灵活的框布局模块,或也称为 Flex 布局。Flexbox 是一个经常用于构建响应式网站的模块。Bulma 是一个免费的开源 CSS 框架,它提供了一系列由社区创建的主题,这些主题都遵循这一个原则,就是尽可能的少写样式。由于使用了 Sass 构建,它实现起来非常简单,而且可以自定义。由于 Bulma CSS 代码的简单性,用它构建的网站通常与所有浏览器兼容,几乎没有问题。目前,它是开发者中最流行的 CSS 框架之一,而且看起来在 2021 年里面还是会保持这一个地位。Tailwind CSS 框架已经存在一段时间了,但是在 2020 年才得到更高的关注度。如果我们看谷歌的热度趋势图,我们可以看 Tailwind CSS 的热度还在持续的往上升。Tailwind 的特别之处在于它不是一个 UI 工具包,这使它与其他 CSS 框架不同。它没有内置的 UI 组件,相反,Tailwind 提供了一组部件(英文叫 widgets)来快速的开发出 UI 组件或者界面,而这些部件是使用一系列的 class 工具叫 Atomic CSS 。这意味着我们可以按照自己的需求从头开始构建或者自定义开发 UI 组件,而不被其他 CSS 框架提供的主题和样式所限制。不过,我们需要熟悉这套 Atomic CSS 工具,这就使得对开发者来说使用 Tailwind 会更有一点挑战性和学习曲线。好的一面就是,它会给你最自由的 UI 开发体验。
在 2020 年里面,前端领域依然在高速发展中。新的技术在不停的涌出,已有的技术和框架也在不断的更新迭代。随着技术的发展,前端这个领域在 2021 年里面依然会技术以光速发展。很多在前端领域的同学在很多群里都会说 “不要再跟新啦,不要再出新的框架啦,学不动了~”所以我们真的所有的新技术都要学吗?并不是的,重点是我们不要为了技术而技术,而是为了解决问题而学一门新技术。我觉得这个很值得我们深思的。重点不是框架那个以后发展更好,而是了解每个框架为什么存在,当下有什么问题导致有了这些框架,以后可能会有什么问题,可能需要什么东西来解决。说到这里很多同学就会问,那么我们应该往哪个方面发展呢?我觉得月影老师说的可以参考:“基础和底层知识,基础和底层知识,基础和底层知识。”因为所有框架也好,新技术也好。我们也不确定以后会出来什么,最后哪个会一统天下,或者那个会默默的隐退江湖。所以重点是我们需要学习,保持可以快速上手任何框架和技术的能力。其实无论是 Vue,React,Angular 还是 Flutter。底层不都是 JavaScript 吗?甚至 Node.js 也是。然后更底层呢?不就是计算机基础知识吗?如果我们这些学通透了,那么以后出来什么各种花样,难道我们不能在一周内学会吗?(可能不能一周内,但是快速上手还是可以的嘛)基础知识还有像数学,这些都是永世不会变的知识。而往往这些知识都是我们开发者的基础。而这些基础才是我们真正能适应这个技术高速发展的时代。也是这些基础让我们不会害怕任何的变化。因为我们拥有可以适应任何变化的能力。我们需要关注前端每年的发展、热点、和趋势。但是不需要盲目的跟风,甚至去学习新的东西。更多是观望这些科技的发展,了解它们,当我们需要用到它们的时候再去深度学习它们,解决我们当下在项目中遇到的问题。这个才是正确的方向和心态。 作者简介:在一线工作五年的程序员,起步于 PHP,最后转型专研前端。Vue、React 使用者,专于 Web 和移动端开发。担任过技术合伙人、研发主管、技术总监等职位。也做过前端和后端的开发和架构设计。有丰富的商城、ERP、CRM 系统研发经验。并且有搭建和管理过 20 人的技术团队。本人非常热爱开源,在 GitHub 上有开源的项目、工具、组件等。从 2020 年头开始写博客至今,一年内在多个博客平台上获得了 “优秀作者奖”、“原力突破 Top 15”、“原力王者 Top 10”、“学习力周榜榜单”、“CSDN 博客专家” 等荣誉。程序员如何避免陷入“内卷”、选择什么技术最有前景,中国开发者现状与技术趋势究竟是什么样?快来参与「2020 中国开发者大调查」,更有丰富奖品送不停!
☞一行代码没写,凭啥被尊为“第一位程序员”?
☞程序员硬核“年终大扫除”,清理了数据库 70GB 空间
☞“我用 72 小时复刻了一个 ClubHouse”